#pragma once

#include <iostream>
#include <string>
#include <sys/epoll.h>
#include <memory>
#include "InetAddr.hpp"
#include "Logger.hpp"
#include "Socket.hpp"

static const int gsize = 64;

class EpollServer
{
public:
    EpollServer(uint16_t port)
        : _listensock(std::make_unique<TcpSocket>()),
          _epfd(-1)
    {
        _listensock->BuildListenSocketMethod(port);
        _epfd = epoll_create(128);
        if (_epfd < 0)
        {
            LOG(LogLevel::FATAL) << "create error!";
            return;
        }
        // 首先要把唯一的sockfd传到epoll模型中
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _listensock->Sockfd();
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock->Sockfd(), &ev);
        (void)n;
    }
    void Accepter()
    {
        InetAddr clientaddr;
        int sockfd = _listensock->AcceptSocketOrDie(&clientaddr);
        if (sockfd > 0)
        {
            struct epoll_event ev;
            ev.events = EPOLLIN;
            ev.data.fd = sockfd;
            int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sockfd, &ev);
            (void)n;
        }
    }
    void Recver(int sockfd)
    {
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "Client Say@ " << buffer;
            std::string echo_string = "echo server# ";
            echo_string += buffer;

            // 写？
            send(sockfd, echo_string.c_str(), echo_string.size(), 0);
        }
        else if (n == 0)
        {
            LOG(LogLevel::INFO) << "client quit, me too, fd is : " << sockfd;
            // 坑: epoll_ctl EPOLL_CTL_DEL : 不能对非法fd进行操作！
            int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
            (void)n;
            close(sockfd);
        }
        else
        {
            LOG(LogLevel::INFO) << "recv error, fd is : " << sockfd;
            // 坑: epoll_ctl EPOLL_CTL_DEL : 不能对非法fd进行操作！
            int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
            (void)n;
            close(sockfd);
        }
    }
    void Dispatcher(int num)
    {
        for (int i = 0; i < num; i++)
        {
            int fd = _revs[i].data.fd;
            uint32_t event = _revs[i].events;
            if (event & EPOLLIN)
            {
                if (fd == _listensock->Sockfd())
                {
                    Accepter();
                }
                else
                {
                    Recver(fd);
                }
            }
        }
    }
    void Start()
    {
        int timeout = -1;
        while (true)
        {
            int n = epoll_wait(_epfd, _revs, gsize, timeout);
            switch (n)
            {
            case 0:
                LOG(LogLevel::INFO) << "timeout.....";
                break;
            case -1:
                LOG(LogLevel::FATAL) << "epoll error!";
                break;
            default:
                Dispatcher(n);
                break;
            }
        }
    }
    ~EpollServer()
    {
    }

private:
    std::unique_ptr<Socket> _listensock;
    int _epfd;
    struct epoll_event _revs[gsize];
};